
// 响应式
function defineReative (obj, key, val) {
  // 递归
  observe(val)

  // 创建一个dep和当前key一一对应
  const dep = new Dep()
  // 对传入的obj进行访问拦截
  Object.defineProperty(obj, key, {
    get() {
      console.log('get', key)
      // 依赖收集再这里
      Dep.target && dep.addDep(Dep.target)
      return val
    },
    set (newVal) {
      console.log('newVal', newVal)
      if (newVal !== val) {
        val = newVal
        observe(newVal)
      }

      // watchers.forEach(w => w.update())
      dep.notify() 
     }
  })
}


class Observer {
  constructor(value) {
    this.value = value

    // 判断器类型
    if (typeof value === 'object') {
      this.walk(value)
    }
  }

  // 对象
  walk (obj) {
    Object.keys(obj).forEach(key => {
      defineReative(obj, key, obj[key])
    })
  }

  // 数组相应化待补充

}

// 对象
function observe(obj) {
  if (typeof obj !== 'object' || obj == null) {
    return
  }
  // Object.keys(obj).forEach(key => {
  //   defineReative(obj, key, obj[key])
  // })

  // 创建一个Observer 实例 （分辨数据对想法还是数组）
  new Observer(obj)

}

// 简易版set
function set(obj, key , val) {
  defineReative(obj, key, val)
}

// 代理函数， 方便用户直接访问$data中的数据
 function proxy (vm, sourceKey) {
  Object.keys(vm[sourceKey]).forEach(key => {
    // 将$data中的key代理到了vm属性中 
    Object.defineProperty(vm, key, {
      get () {
        return vm[sourceKey][key]
      },
      set (newValue) {
        vm[sourceKey][key] = newValue
      }
    })
  })
 }


// 创建Kvue构造函数
class Kvue {
  constructor (options) {
    // 保存选项
    this.$options = options
    this.$data = options.data
    this.$methods = options.methods
    this.$created = options.created
    // 给data 做相应话处理
    observe(this.$data)
    // 代理
    proxy(this, '$data')
    // 创建一个编译器实例
    this.$created.apply(this)
    console.log('this.$created')
    new Compile(options.el, this)
  }
}

// let watchers = []
// 创建观察者 保存更新函数，数值发生变化调用更新函数
class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm

    this.key = key

    this.updateFn = updateFn

    // watchers.push(this)

    // Dep.target静态属性上设置值为当前watcher实例
    Dep.target = this
    this.vm[this.key] //读取触发了getter
    Dep.target = null  //收集完就制空
  }

  update() {
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}


// 依赖收集 dep 管理某个key相关的所有Watcher实例
class Dep {
  constructor() {
    this.deps = []
  }

  addDep(dep) {
    this.deps.push(dep)
  }

  notify() {
    this.deps.forEach(dep => dep.update())
  }
}
